package yunjiao.javatutorials.designpatterns.command;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @author yangyunjiao
 */
public class CommandInterpreter {
    public static Optional<Command> interpretCommand(String commandStr) {
        Optional<Command> command = Optional.empty();
        if (commandStr != null && !commandStr.trim().isEmpty()) {
            List<String> applianceNames = HomeAutomation.INSTANCE.applianceNames();
            Optional<String> applianceName = findApplianceName(commandStr, applianceNames);
            if (applianceName.isPresent()) {
                List<Command> commands = HomeAutomation.INSTANCE.applianceCommands(applianceName.get());
                command = findCommand(commandStr, commands);
            }
        }
        return command;
    }

    private static Optional<Command> findCommand(String commandStr, List<Command> availableCommands) {
        List<Command> matchingCommands = availableCommands.stream()
                .filter(availableCommand -> hasMatchingKeywords(availableCommand, commandStr))
                .sorted(new Comparator<>() {
                    @Override
                    public int compare(Command cmd1, Command cmd2) {
                        return Integer.compare(noOfMatch(cmd2, commandStr), noOfMatch(cmd1, commandStr));
                    }

                    private int noOfMatch(Command cmd, String commandStr) {
                        return cmd.keywords().stream().filter(keyword -> hasPotentialMatch(keyword, commandStr)).collect(Collectors.toList()).size();
                    }
                }).toList();
        return Optional.ofNullable(matchingCommands.isEmpty() ? null : matchingCommands.get(0));
    }

    private static boolean hasMatchingKeywords(Command command, String commandStr) {
        return command.keywords().stream().anyMatch(keyword -> hasPotentialMatch(keyword, commandStr));
    }

    private static Optional<String> findApplianceName(String commandStr, List<String> applianceNames) {
        return applianceNames.stream().filter(applianceName -> hasPotentialMatch(applianceName, commandStr))
                .findFirst();

    }

    private static boolean hasPotentialMatch(String keyword, String commandStr) {
        return commandStr.toLowerCase().contains(keyword.toLowerCase());
    }
}
